package edu.polsl.bio.str.manager.web;

import edu.polsl.bio.str.manager.logic.DotPlotBean;
import edu.polsl.bio.str.manager.vo.DotPlotResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;

/**
 * //todo class description
 * <p/>
 * Created on: Jul 10, 2011 6:53:57 PM <br/>
 * <a href="http://www.polsl.pl">www.polsl.pl</a>
 *
 * @author lukasz.olczak@polsl.pl
 */
public class DotPlotServlet extends HttpServlet {
  /**
   * slf4j Logger.
   */
  private static final Logger log = LoggerFactory.getLogger(DotPlotServlet.class.getName());

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(this.getServletConfig().getServletContext());

    String action = req.getParameter("action");
    long refId = Long.valueOf(req.getParameter("refId"));
    long queryId = Long.valueOf(req.getParameter("queryId"));
    long refChromId = Long.valueOf(req.getParameter("refChromosomeId"));
    long queryChromId = Long.valueOf(req.getParameter("queryChromosomeId"));
    int width = Integer.valueOf(req.getParameter("width"));
    DotPlotBean dotPlotBean = (DotPlotBean) context.getBean("dotPlotBean");
    if (action.equals("generate")) {
      generateDotPlot(refId, queryId, refChromId, queryChromId, width, dotPlotBean);
    } else if (action.equals("get")) {
      int factor = Integer.valueOf(req.getParameter("factor"));
      int bFactor = Integer.valueOf(req.getParameter("bFactor"));
      getDotPlot(refId, queryId, refChromId, queryChromId, width, dotPlotBean, factor, bFactor, resp);
    } else {
      throw new ServletException("Improper action");
    }
  }

  private void generateDotPlot(final long refId, final long queryId, final long refChromId, final long queryChromId,
                               final int width, final DotPlotBean dotPlotBean) {

    new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          dotPlotBean.generateDotPlot(refId, queryId, refChromId, queryChromId, width);
        } catch (Exception e) {
          log.error("Exception occurred", e);
        }
      }
    }).start();

  }

  private void getDotPlot(long refId, long queryId, long refChromId, long queryChromId,
                          int width, DotPlotBean dotPlotBean, int factor, int bFactor, HttpServletResponse resp) throws ServletException {
    try {
      log.debug("Generating png...");
      DotPlotResult dots = dotPlotBean.getDotPlot(refId, queryId, refChromId, queryChromId, width);
      BufferedImage img = paint(dots, factor, bFactor);

      int length = 0;
      ServletOutputStream op = resp.getOutputStream();

      //
      //  Set the response and go!
      //
      //
      resp.setContentType("image/png");
//        resp.setContentLength( (int)f.length() );
      resp.setHeader("Content-Disposition", "attachment; filename=\"chr" + refChromId + "x" + queryChromId + ".png\"");

      ImageIO.write(img, "png", op);

      op.flush();
      op.close();

    } catch (Exception e) {
      log.error("Exception occurred", e);
      throw new ServletException(e);
    }
  }

  private double pow(double val, int exp) {
    double result = 1;
    for (int i = 0; i < exp; i++) {
      result = result * val;
    }

    return result;
  }

  private BufferedImage paint(DotPlotResult dots, int factor, int bFactor) {
    double[][] dotTab = dots.getForwardDots();
    double[][] backwardDotTab = dots.getBackwardDots();

    double max = 0.0;
    double bMax = 0.0;
    for (int x = 0; x < dotTab.length; x++) {
      for (int y = 0; y < dotTab[0].length; y++) {
        if (dotTab[x][y] > max) {
          max = dotTab[x][y];
        }
        if (backwardDotTab[x][y] > bMax) {
          bMax = backwardDotTab[x][y];
        }
      }
    }

    int width = dotTab.length + 2;
    int height = dotTab[0].length + 2;

    // Create a buffered image in which to draw
    BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

    // Create a graphics contents on the buffered image
    Graphics2D g2d = bufferedImage.createGraphics();

    // Draw graphics
    g2d.setColor(Color.WHITE);
    g2d.fillRect(0, 0, width, height);
    g2d.setColor(Color.BLACK);
    g2d.drawLine(0, 0, 0, height);
    g2d.drawLine(0, 0, width, 0);

    for (int x = 0; x < dotTab.length; x++) {
      for (int y = 0; y < dotTab[0].length; y++) {
        //backward
        double intensity = (1 - backwardDotTab[x][y] / bMax);
        intensity = pow(intensity, bFactor);
        if (backwardDotTab[x][y] > 0.0) {
          g2d.setColor(new Color((float) intensity, 1.0f, 1.0f, 1.0f));
//          g2d.setColor(Color.BLACK);
          g2d.drawLine(x + 1, y + 1, x + 1, y + 1);
        }
        //forward
        intensity = (1 - dotTab[x][y] / max);
        intensity = pow(intensity, factor);
        if (dotTab[x][y] > 0.0) {
          g2d.setColor(new Color((float) intensity, (float) intensity, (float) intensity, 0.5f));
//          g2d.setColor(Color.BLACK);
          g2d.drawLine(x + 1, y + 1, x + 1, y + 1);
        }

        
      }
    }

    // Graphics context no longer needed so dispose it
    g2d.dispose();

    return bufferedImage;
  }
}
